﻿//-----------------------------------------------------------------------
// <copyright file="Class1{T}.cs" company="My Company">
//     Custom company copyright tag.
// </copyright>
//-----------------------------------------------------------------------

namespace HashMaster.Agent.Neo
{
    using System;
    using System.Threading;
    using System.IO;
    using HashMaster.Lib;
    using System.Security.Principal;
    using System.Diagnostics;
    using System.Reflection;

    class Program
    {
        static HashProcess hp;
        internal static FileSystemWatcher watcher ;
        static byte[] buffMin = new byte[8];
        static byte[] buffSkip = new byte[8];

        private static DateTime LastProcessChangedTime =DateTime.Now;

        static WindowsIdentity wi;
        static WindowsPrincipal wp;

        private static bool IsRunAsAdministrator()
        {
            wi = WindowsIdentity.GetCurrent();
            wp = new WindowsPrincipal(wi);

            return wp.IsInRole(WindowsBuiltInRole.Administrator);
        }

        static void Main(string[] args)
        {
            if (IsRunAsAdministrator())
            {
                // It is not possible to launch a ClickOnce app as administrator directly, so instead we launch the
                // app as administrator in a new process.
                var processInfo = new ProcessStartInfo(Assembly.GetExecutingAssembly().CodeBase);

                // The following properties run the new process as administrator
                processInfo.UseShellExecute = true;
                processInfo.Verb = "runas";

                // Start the new process
                try
                {
                    Process.Start(processInfo);
                }
                catch (Exception)
                {
                    // The user did not allow the application to run as administrator
                    Console.WriteLine("Sorry, this application must be run as Administrator.");
                }

                // Shut down the current process
                Environment.Exit(3);
            }
            else
            {
                // We are running as administrator

                // Do normal startup stuff...
            }

            #region 程序初始化

            ///通过reset参数重置用户信息
            ///当前只有userid是变量
            if (args.Length>0&&args[0]=="reset")
            {
                Utility.ClientData.ClientName = string.Empty;
            }


            ///设置客户端id
            if (Utility.ClientData.MacAddress == string.Empty)
            {
                Console.WriteLine("无法获取网卡的mac地址，按任意键退出。");
                Console.ReadLine();
                Environment.Exit(0);
            }
            while (string.IsNullOrEmpty(Utility.ClientData.ClientName))
            {
                Console.Clear();
                Console.WriteLine("请指定一个客户端名称，不分大小写（例 pc-01）:");
                Utility.ClientData.ClientName = Console.ReadLine().ToUpper();
            }
            #endregion
            /*
            Console.WriteLine("请输入序号选择Hashcat的进程优先级");
            Console.WriteLine("1 - Realtime");
            Console.WriteLine("2 - High");
            Console.WriteLine("3 - Above Normal");
            Console.WriteLine("4 - Normal");

            switch (Console.Read())
            {
                case '1':
                    Utility.HashcatPriority = ProcessPriorityClass.RealTime;
                    break;
                case '2':
                    Utility.HashcatPriority = ProcessPriorityClass.High;
                    break;
                case '3':
                    Utility.HashcatPriority = ProcessPriorityClass.AboveNormal;
                    break;
                case '4':
                    Utility.HashcatPriority = ProcessPriorityClass.Normal;
                    break;

                default:
                    Environment.Exit(2);
                    break;
            }
            */
  
           Utility.HashcatPriority = ProcessPriorityClass.AboveNormal;

            //客户端信息设置完成
            //向服务器请求身份
            Console.WriteLine(Utility.ServiceUrl);
            while (Utility.ClientSync() != true) { }
            
           

            //服务器空job强退


            //当新jobid==0时 认为没有可用任务 每分钟检查
            while (Utility.ClientData.JobId == 0)
            {
                Console.WriteLine(">>No Job Availible. retry after 60 sec." + DateTime.Now.ToString());
                Thread.Sleep(60000);
                
                Utility.ClientSync();
            }

            
            //创建hashprocess对象
            hp = new HashProcess();
            hp.StatusChanged += new HashProcess.StatusChangeddHandle(hp_StatusChanged);


            //请求任务
            hp.StartJob(Utility.ClientData);

            while (true) { Thread.Sleep(200); }
        }


        /// <summary>
        /// 读取restore文件获取当前进度
        /// </summary>
        /// <param name="restorePath">restore文件路径</param>
        /// <param name="jobData">获取slicewidth的对象</param>
        /// <returns></returns>
        static double GetJobProcess(string restorePath ,ClientSyncData jobData)
        {
            try
            {
                using (FileStream fs = new FileStream(restorePath, FileMode.Open,FileAccess.Read,FileShare.ReadWrite))
                {
                    buffMin = new byte[8];
                    buffSkip = new byte[8];
                    fs.Position = 7944;
                    fs.Read(buffMin, 0, 8);
                    fs.Read(buffSkip, 0, 8);
                    fs.Position = 7957;

                    fs.Close();

                    HashcatRestoreFile restore;
                    restore.Password_Min = BitConverter.ToUInt32(buffMin, 0);
                    restore.Password_Skip = BitConverter.ToUInt64(buffSkip, 0);

                    UInt64 max = (UInt64)(Math.Pow(10, 15) / jobData.SliceWidth / 100);
                    return ((double)restore.Password_Skip * 100 / max);
                }
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message);
                return 0;
            }
        }


        internal static void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            double ret = GetJobProcess(e.FullPath, Utility.ClientData);

            
            if (ret - Utility.ClientData.Progress != 0)
            {
                Console.Write("{0}%",ret );
                Utility.ClientData.Progress = ret;
                Utility.ClientSync();

                //LastProcessChangedTime = DateTime.Now;
            }
            else
            {

                Console.Write("({0})", DateTime.Now.Subtract(LastProcessChangedTime).TotalSeconds);
            }

            Console.Write(".");
            if (Utility.NeedForceStop || DateTime.Now.Subtract(LastProcessChangedTime).TotalMinutes > 2)
            {
                hp.EndCurrentJob();
            }

            
        }

        static void hp_StatusChanged(Lib.EnumStatus status)
        {
            switch (status)
            {
                case HashMaster.Lib.EnumStatus.Pending:
                    Console.WriteLine("\r\n>>Job Killed");
                    
                    //任务被强制退出 强制确认通讯成功才继续
                    while (Utility.ClientSync() != true) { }
                    
                    //当新jobid==0时 认为没有可用任务 每分钟检查
                    while (Utility.ClientData.JobId == 0)
                    {
                        Console.WriteLine(">>No Job Availible. retry after 60 sec." + DateTime.Now.ToString());
                        Thread.Sleep(300000);
                        Utility.ClientSync();
                    }
                    hp.StartJob(Utility.ClientData);
                    //ProcessMonitorThread.Abort();
                    break;
                case HashMaster.Lib.EnumStatus.Started:
                    //任务启动 开启进度监视进程
                    Console.WriteLine("\r\n>>Job Started: " + Utility.ClientData.JobId.ToString());

                    try
                    {
                        Console.WriteLine("Try to dispose watcher");
                        watcher.Dispose();
                    }
                    catch (Exception)
                    {

                        Console.WriteLine("Clean watcher failed.");
                    }

                    //创建watcher监视restore文件
                    watcher = new FileSystemWatcher();
                    watcher.Path = Utility.HashcatPath;
                    watcher.NotifyFilter = NotifyFilters.CreationTime;
                    watcher.Filter = Utility.ClientData.JobId.ToString() + ".restore";
                    watcher.Changed += new FileSystemEventHandler(watcher_Changed);
                    watcher.EnableRaisingEvents = true;


                    break;
                case HashMaster.Lib.EnumStatus.Suspend:
                    break;
                case HashMaster.Lib.EnumStatus.Finished:
                    //任务正常完成
                    Console.WriteLine("\r\n>>Job Finished");
                    Utility.ClientData.Progress = 100;
                    //结束任务情况下 强制确认通讯成功才继续
                    while (Utility.ClientSync() != true) { }
                    //当新jobid==0时 认为没有可用任务 每分钟检查
                    while (Utility.ClientData.JobId==0)
                    {                    
                        Console.WriteLine(">>No Job Availible. retry after 60 sec. " + DateTime.Now.ToString());
                        Thread.Sleep(300000);
                        Utility.ClientSync();
                    }
                    hp.StartJob(Utility.ClientData);

                    break;
                default:
                    break;
            }
        }



        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        struct HashcatRestoreFile
        {
            /// 注释未使用的变量
            //public uint Version_Bin;
            //public string CurrentWorkDirectory;
            //public uint ArgumentCount;

            public uint Password_Min;
            public UInt64 Password_Skip;
            //public uint ProcessId;
            //public string UnUsed;
        }

    }
}
